package com.soft.util.encrypt;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.Charset;
import java.util.Arrays;


/**
 * @author slduan
 * Aes
 * */
public class Aes
{
    private final static String AES = "AES";

    /**
     * AES加密
     *
     * @param content 需要加密的内容
     * @param password 解密密钥
     * @return
     */
    public static String encryptAes(String content, String password)
    {
        try
        {
            byte[] compBefore = password.getBytes();
            byte[] compAfter = Arrays.copyOf(compBefore, 24);
            SecretKeySpec key = new SecretKeySpec(compBefore, AES);
            Cipher cipher = Cipher.getInstance(AES_CBC_NOPADDING);
            byte[] byteContent = content.getBytes("utf-8");
            cipher.init(Cipher.ENCRYPT_MODE, key);
            byte[] encryptResult = cipher.doFinal(byteContent);
            String result = Base64.encode(parseByte2HexStr(encryptResult));
            return result;
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * AES解密
     *
     * @param content 待解密内容
     * @param password 解密密钥
     * @return
     */
    public static String decryptAes(String content, String password)
    {
        try
        {
            byte[] compBefore = password.getBytes();
            byte[] compAfter = Arrays.copyOf(compBefore, 24);
            SecretKeySpec key = new SecretKeySpec(compBefore, AES);
            Cipher cipher = Cipher.getInstance(AES_CBC_NOPADDING);
            cipher.init(Cipher.DECRYPT_MODE, key);
            byte[] decryptResult = cipher.doFinal(parseHexStr2Byte(new String(Base64.decode(content))));
            return new String(decryptResult,"UTF-8");
        }
        catch (Exception e)
        {
            e.printStackTrace();
            return null;
        }
    }


    public static void main(String[] args) {
        String str = decryptAes("MTI5OTg3OTI0MDg3M2EyODY5ODU0YWY0ZTJjMjcxN2I4MzQ0YjM2NzQ3MGM5ZTFhZWVjZTFlOGRiZDFkZDM0MjM3OTJjZWViOTdjYjBiMzI3ZWVhZjBiOTc1MjhlYTNl","65e11f59fb55d57a54aeb9913e66b702");
        System.out.println(str);
    }
    /**
     * 将二进制转换成16进制
     *
     * @param buf
     * @return
     */
    private static String parseByte2HexStr(byte[] buf)
    {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < buf.length; i++)
        {
            String hex = Integer.toHexString(buf[i] & 0xFF);
            if (hex.length() == 1)
            {
                hex = '0' + hex;
            }
            sb.append(hex.toUpperCase());
        }
        return sb.toString().toLowerCase();
    }

    /**
     * 将16进制转换为二进制
     *
     * @param hexStr
     * @return
     */
    private static byte[] parseHexStr2Byte(String hexStr)
    {
        if (hexStr.length() < 1){
            return null;
        }
        byte[] result = new byte[hexStr.length() / 2];
        for (int i = 0; i < hexStr.length() / 2; i++)
        {
            int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16);
            int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16);
            result[i] = (byte) (high * 16 + low);
        }
        return result;
    }

    public static final Charset CHARSET = Charset.forName("utf-8");

    public static final byte KEY_STRSZIE = 16;

    public static final String ALGORITHM = "AES";

    public static final String AES_CBC_NOPADDING = "Aes/ECB/PKCS5Padding";



    /**`
     * 为了平台的通用，选择 Aes/CBC/NoPadding 的模式，然后手动 padding
     * 对应PHP 平台为 mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $data, MCRYPT_MODE_CBC, $iv)
     *
     * Aes/CBC/NoPadding encrypt
     * 16 bytes secretKeyStr
     * 16 bytes intVector
     *
     * @param
     * @param
     * @param input
     * @return
     */
    public static byte[] encryptCbcNoPadding(byte[] secretKeyBytes, byte[] intVectorBytes, byte[] input) {
        try {
            IvParameterSpec iv = new IvParameterSpec(intVectorBytes);
            SecretKey secretKey = new SecretKeySpec(secretKeyBytes, ALGORITHM);
            int inputLength = input.length;
            int srcLength;

            Cipher cipher = Cipher.getInstance(AES_CBC_NOPADDING);
            int blockSize = cipher.getBlockSize();
            byte[] srcBytes;
            if (0 != inputLength % blockSize) {
                srcLength = inputLength + (blockSize - inputLength % blockSize);
                srcBytes = new byte[srcLength];
                System.arraycopy(input, 0, srcBytes, 0, inputLength);
            } else {
                srcBytes = input;
            }

            cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
            byte[] encryptBytes = cipher.doFinal(srcBytes);
            return encryptBytes;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * Aes/CBC/NoPadding decrypt
     * 16 bytes secretKeyStr
     * 16 bytes intVector
     *
     * @param
     * @param
     * @param input
     * @return
     */
    public static byte[] decryptCbcNoPadding(byte[] secretKeyBytes, byte[] intVectorBytes, byte[] input) {
        try {
            IvParameterSpec iv = new IvParameterSpec(intVectorBytes);
            SecretKey secretKey = new SecretKeySpec(secretKeyBytes, ALGORITHM);

            Cipher cipher = Cipher.getInstance(AES_CBC_NOPADDING);
            cipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
            byte[] encryptBytes = cipher.doFinal(input);
            return encryptBytes;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 用 Aes 算法加密 inputStr。
     * 使用 secretStr 作为 key，secretStr 的前 16 个字节作为 iv。
     *
     * @param secretStr
     * @param inputStr
     * @return
     */
    public static byte[] encode(String secretStr, String inputStr) {
        if (KEY_STRSZIE > secretStr.length()) {
            return null;
        }
        byte[] secretKeyBytes = secretStr.getBytes(CHARSET);
        secretKeyBytes = Arrays.copyOfRange(secretKeyBytes, 0, 16);
        byte[] ivBytes = Arrays.copyOfRange(secretKeyBytes, 0, 16);
        byte[] inputBytes = inputStr.getBytes(CHARSET);

        byte[] outputBytes = encryptCbcNoPadding(secretKeyBytes, ivBytes, inputBytes);
        return outputBytes;
    }


    /**
     * 用 Aes 算法加密 inputStr。
     * 使用 secretStr 作为 key，secretStr 的前 16 个字节作为 iv。
     * 并对加密后的字节数组调用 sun.misc.BASE64Encoder.encode 方法，
     * 转换成 base64 字符串返回。
     *
     * @param secretStr
     * @param inputStr
     * @return
     * @throws
     */
    public static String strEncodBase64(String secretStr, String inputStr){
        String base64Str = Base64.encode(encode(secretStr, inputStr));
        return base64Str;
    }

    /**
     * 用 Aes 算法加密 inputStr。
     * 使用 secretStr 作为 key，secretStr 的前 16 个字节作为 iv。
     *
     * @param secretStr
     * @param
     * @return
     * @throws
     */
    public static byte[] decode(String secretStr, byte[] inputBytes){
        if (KEY_STRSZIE > secretStr.length()) {
            return null;
        }
        byte[] secretKeyBytes = secretStr.getBytes(CHARSET);
        secretKeyBytes = Arrays.copyOfRange(secretKeyBytes, 0, 16);
        byte[] ivBytes = Arrays.copyOfRange(secretKeyBytes, 0, 16);

        byte[] outputBytes = decryptCbcNoPadding(secretKeyBytes, ivBytes, inputBytes);
        return outputBytes;
    }

    /**
     * 用 Aes 算法解密 inputStr。
     *
     *
     * @param secretStr
     * @param inputStr
     */
    public static String base64StrDecode(String secretStr, String inputStr){
        byte[] inputBytes;
        inputBytes = Base64.decode(inputStr);
        String outputStr = new String(decode(secretStr, inputBytes), CHARSET);
        return outputStr;
    }
}
